From 3d521e933e1b3f3f62c12542e2fea98e77169838 Mon Sep 17 00:00:00 2001 From: Keir Fraser Date: Tue, 6 Apr 2010 06:52:11 +0100 Subject: [PATCH] cpuidle: mwait on softirq_pending & remove wakeup ipis For cpu which enter deep C state via monitor/mwait, wakeup can be done by writing to the monitored memory. So once monitor softirq_pending, we can remove the redundant ipis. Signed-off-by: Yu Ke Signed-off-by: Wei Gang --- xen/arch/x86/acpi/cpu_idle.c | 45 ++++++++++++++++++++++++++++++++++-- xen/arch/x86/hpet.c | 2 ++ xen/include/xen/cpuidle.h | 2 ++ 3 files changed, 47 insertions(+), 2 deletions(-) diff --git a/xen/arch/x86/acpi/cpu_idle.c b/xen/arch/x86/acpi/cpu_idle.c index 51227842e4..bd4d68a14d 100644 --- a/xen/arch/x86/acpi/cpu_idle.c +++ b/xen/arch/x86/acpi/cpu_idle.c @@ -69,6 +69,14 @@ boolean_param("lapic_timer_c2_ok", local_apic_timer_c2_ok); static struct acpi_processor_power *__read_mostly processor_powers[NR_CPUS]; +static char* acpi_cstate_method_name[] = +{ + "NONE", + "SYSIO", + "FFH", + "HALT" +}; + static void print_acpi_power(uint32_t cpu, struct acpi_processor_power *power) { uint32_t i, idle_usage = 0; @@ -92,6 +100,7 @@ static void print_acpi_power(uint32_t cpu, struct acpi_processor_power *power) printk("type[C%d] ", power->states[i].type); printk("latency[%03d] ", power->states[i].latency); printk("usage[%08d] ", power->states[i].usage); + printk("method[%5s] ", acpi_cstate_method_name[power->states[i].entry_method]); printk("duration[%"PRId64"]\n", res); } printk(" C0:\tusage[%08d] duration[%"PRId64"]\n", @@ -140,11 +149,43 @@ static void acpi_safe_halt(void) #define MWAIT_ECX_INTERRUPT_BREAK (0x1) +/* + * The bit is set iff cpu use monitor/mwait to enter C state + * with this flag set, CPU can be waken up from C state + * by writing to specific memory address, instead of sending IPI + */ +static cpumask_t cpuidle_mwait_flags; + +void cpuidle_wakeup_mwait(cpumask_t *mask) +{ + cpumask_t target; + int cpu; + + cpus_and(target, *mask, cpuidle_mwait_flags); + + /* cpu is 'mwait'ing at softirq_pending, + writing to it will wake up CPU */ + for_each_cpu_mask(cpu, target) + set_bit(TIMER_SOFTIRQ, &softirq_pending(cpu)); + + cpus_andnot(*mask, *mask, cpuidle_mwait_flags); +} + static void mwait_idle_with_hints(unsigned long eax, unsigned long ecx) { - __monitor((void *)current, 0, 0); + int cpu = smp_processor_id(); + + __monitor((void *)&softirq_pending(cpu), 0, 0); + smp_mb(); - __mwait(eax, ecx); + if (!softirq_pending(cpu)) + { + cpu_set(cpu, cpuidle_mwait_flags); + + __mwait(eax, ecx); + + cpu_clear(cpu, cpuidle_mwait_flags); + } } static void acpi_processor_ffh_cstate_enter(struct acpi_processor_cx *cx) diff --git a/xen/arch/x86/hpet.c b/xen/arch/x86/hpet.c index 0e099de8ec..1cedb1cb3c 100644 --- a/xen/arch/x86/hpet.c +++ b/xen/arch/x86/hpet.c @@ -166,6 +166,8 @@ static int evt_do_broadcast(cpumask_t mask) ret = 1; } + cpuidle_wakeup_mwait(&mask); + if ( !cpus_empty(mask) ) { cpumask_raise_softirq(mask, TIMER_SOFTIRQ); diff --git a/xen/include/xen/cpuidle.h b/xen/include/xen/cpuidle.h index 4f4a2995ca..1f8c3b5ae4 100644 --- a/xen/include/xen/cpuidle.h +++ b/xen/include/xen/cpuidle.h @@ -86,6 +86,8 @@ struct cpuidle_governor extern struct cpuidle_governor *cpuidle_current_governor; void cpuidle_disable_deep_cstate(void); +extern void cpuidle_wakeup_mwait(cpumask_t *mask); + #define CPUIDLE_DRIVER_STATE_START 1 #endif /* _XEN_CPUIDLE_H */ -- 2.30.2